#include <iostream>
#include<fcntl.h>
#include<unistd.h>
#include<ctime>
#define maxsize 200
#define Maxindex 100
using namespace std;
struct index
{
    std::string key;
    int32_t offset;
    int32_t time_out; 
};
index Index[Maxindex];
int32_t num_index = 0;
class KVDBHandler { 
 public: 
 int32_t fd;
 KVDBHandler(const std::string& db_file){
     const char* path = db_file.c_str();
      fd = open(path, O_RDWR|O_CREAT|O_APPEND , S_IRUSR|S_IWUSR);
     if(fd == -1){
          cout << "path wrong" << endl; 
     }
 };
 ~KVDBHandler(){close(fd);};
 int32_t set(const std::string& key, const std::string& value) 
 {   
     int32_t flag = 0;
          for(int32_t i = 0; i < num_index; i++){
              if(key == Index[i].key){
                Index[i].offset = lseek(fd , 0 , SEEK_END);
                Index[num_index].time_out = 0; 
                flag = 1;
                break;
              }
              }
              if(flag == 0){
                  Index[num_index].key = key;
                  Index[num_index].offset = lseek(fd , 0 , SEEK_END);
                  Index[num_index].time_out = 0;
                  num_index++;
              }       
     int32_t num_key[1]; 
     num_key[0] = key.length();
     write(fd, num_key , 4);
     int32_t num_value[1]; 
     num_value[0] = value.length();
     write(fd, num_value , 4);
     const char *key_val = key.c_str();
     const char *value_val = value.c_str();
     write(fd , key_val , key.length());
     write(fd , value_val , value.length());
        return true;
     }
char* get(const std::string& key) const{
    char* sub_value = new char[256];
int32_t flag = 0;
for(int32_t i = 0 ; i < num_index; i++){
    if(Index[i].key == key && Index[i].offset != -1){
        flag = 1;
        lseek(fd , Index[i].offset , SEEK_SET);
        break;
    }
}
if(flag){
    int32_t len_key,len_value;
    char* sub_key = new char[32];
         read(fd,&len_key,sizeof(len_key));
         read(fd,&len_value,sizeof(len_value));
         read(fd,sub_key,len_key);
         read(fd,sub_value,len_value);
          delete sub_key;
}
else{cout << "not get" << endl;}
return sub_value;
delete sub_value;
}
int32_t del(const std::string& key){
     int num_key[1]; 
     num_key[0] = key.length();
     write(fd, num_key , 4);
     int num_value[1]; 
     num_value[0] = -1;
     write(fd, num_value , 4);
     const char *key_val = key.c_str();
     write(fd , key_val , key.length());
     const char* value_val = new char[256];
     write(fd , value_val , sizeof(int32_t));
     delete value_val;
        for(int32_t i = 0; i < num_index; i++){
              if(key_val == Index[i].key){
                  Index[i].offset = -1;
                break;
              }
              }
     return true;
     }

int purge(KVDBHandler &purgetest){
    int32_t fd_val = purgetest.fd;
         if(fd_val == -1) {
           cout << "open wrong";
           return 0;
         }
         else {
            int32_t flag = 1;   
            string *key = new string [100];
            int32_t num_key = num_index;
            for(int i = 0; i < num_key; i++)
            key[i] = Index[i].key;
        for(int32_t i = 0; i < num_key; i++)
       {
           if(get(key[i])[0]){
            flag = purgetest.set(key[i] , get(key[i]));
            if(!flag){break;} 
           }
       }
             if(flag){
                 return 1;
             }
             else {
                 cout << "no space" << endl;
                 return 0;
             }
         }
}
int expires(const std::string& key , int n){
     int32_t flag = -1;
for(int32_t i = 0 ; i < num_index; i++){
    if(Index[i].key == key && Index[i].offset != -1){
        flag = i;
        lseek(fd , Index[i].offset , SEEK_SET);
        break;
    }
}
if(flag == -1){cout << "not this key" << endl; return 0;}
else{
    time_t time_cur = time(&time_cur);
    Index[flag].time_out = time_cur + n;
    return 1;
}
}
void check(){
     for(int i = 0; i < num_index; i++){
         if(Index[i].time_out != 0){
             time_t time_cur = time(&time_cur);
             if(time_cur >=Index[i].time_out) {if(Index[i].offset != -1) del(Index[i].key);break;}

         }
     }
}
 };

int main(){
    KVDBHandler test("1111") , afterpurge("kv");
    // index *Index = new index [100];
    int t , time_val;
    time_t time_cur = time(&time_cur);
    cin >> t;
     time_t time_cur2 = time(&time_cur2);
    time_t time_real = time_cur2 - time_cur;
    string key_val , value_val , order;
    while(t--){
      cin >> order >> key_val;
      if(key_val.length() == 0){cout << "wrong key" << endl;continue;}
      if(order == "set"){
          cin >> value_val;
          if(value_val.length() == 0){cout << "wrong value" << endl;continue;}
          
          test.set(key_val , value_val);
      }
      else if(order == "get"){
        // //   char *value_val = new char [256];
        // //   test.get(key_val, value_val);
          char *value_val = test.get(key_val);
          if(value_val[0]) cout << value_val << endl;
        //   else cout << "get false" << endl;
      }
      else if(order == "del"){
          test.del(key_val);
          }
      else if(order == "expires"){
          cin >> time_val;
          test.expires(key_val , time_val);
      }
      test.check();
    }
	//从文件头偏移到文件尾，lseek返回的偏移量就是文件大小
	int32_t res = lseek(test.fd, 0, SEEK_END);
	if(res > maxsize) {
        int32_t flag = test.purge(afterpurge);
        if(flag){
            test.fd = afterpurge.fd;
            remove("1111");
            // KVDBHandler tag("1111");
            // afterpurge.fd = tag.fd;
        }
        }
    //     //检查index正确性
    // cout << num_index << endl;
    // for(int32_t i = 0; i < num_index; i++)
    // cout << Index[i].key << " " << Index[i].offset << endl;
    // delete [] Index;
    }